<?php
/**
 * Created by PhpStorm.
 * User: hongtianjin
 * Date: 2017/2/27 0027
 * Time: 10:48
 */

namespace App\App\Services;

use App\Models\Prize\PrizeService;
use App\Models\PrizePayment\PrizePayment;
use App\Models\PrizePayment\PrizePaymentService;
use App\Support\Helpers\HttpHelper;
use App\Support\Helpers\UtilsHelper;
use EasyWeChat\Foundation\Application as WeChatApplication;
use EasyWeChat\Payment\Order;
use Illuminate\Support\Facades\Log;

class WechatService
{
    /*
     * @var WeChatApplication
     */
    private $weChatApplication;

    /*
     * @var PrizePaymentService
     */
    private $prizePaymentService;

    /*
     * @var PrizeService
     */
    private $prizeService;

    /**
     * 微信
     */
    public function __construct(WeChatApplication $weChatApplication, PrizePaymentService $prizePaymentService, PrizeService $prizeService)
    {
        $this->weChatApplication = $weChatApplication;
        $this->prizePaymentService = $prizePaymentService;
        $this->prizeService = $prizeService;
    }

    /**
     * 微信授权
     * @return
     */
    public function getWechatApp()
    {
        return $this->weChatApplication;
    }

    /**
     * 发红包
     *
     * @param $activity
     * @param $record
     *
     * @return array|bool|null
     */
    public function send($activity, $record)
    {
        $mTime = microtime(true) * 10000;
        $randStr = substr($mTime, 10);
        $conf = config('wechat.red_pack');
        $fee = floatval($record['redpack']) * 100;
        $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack';
        $pars = [];
        $pars['nonce_str'] = md5(UtilsHelper::random(3) . $mTime);
        $pars['mch_billno'] = $conf['mch_id'] . date('YmdHis') . $randStr;
        $pars['mch_id'] = $conf['mch_id'];
        $pars['wxappid'] = $conf['wxappid'];
        $pars['send_name'] = $activity['provider'];
        $pars['re_openid'] = $record['openid'];
        $pars['total_amount'] = $fee;
        $pars['total_num'] = 1;
        $pars['wishing'] = $activity['wish'];
        $pars['client_ip'] = GetHostByName($_SERVER['SERVER_NAME']);
        $pars['act_name'] = $activity['name'];
        $pars['remark'] = $activity['remark'];
        $pars['sign'] = $this->sign($pars, $conf['password']);

        $xml = UtilsHelper::array2xml($pars);
        $extras = [];
        $extras['CURLOPT_CAINFO'] = $conf['rootca'];
        $extras['CURLOPT_SSLCERT'] = $conf['apiclient_cert'];
        $extras['CURLOPT_SSLKEY'] = $conf['apiclient_key'];

        $procResult = null;
        $resp = HttpHelper::ihttp_request($url, $xml, $extras);
        if (UtilsHelper::is_error($resp)) {
            $procResult = $resp;
        } else {
            $xml = '<?xml version="1.0" encoding="utf-8"?>' . $resp['content'];
            $dom = new \DOMDocument();
            if ($dom->loadXML($xml)) {
                $xpath = new \DOMXPath($dom);
                $code = $xpath->evaluate('string(//xml/return_code)');
                $ret = $xpath->evaluate('string(//xml/result_code)');
                if (strtolower($code) == 'success' && strtolower($ret) == 'success') {
                    $procResult = true;
                } else {
                    $error = $xpath->evaluate('string(//xml/err_code_des)');
                    $procResult = UtilsHelper::error(-2, $error);
                }
            } else {
                $procResult = UtilsHelper::error(-1, 'error response');
            }
        }
        if (UtilsHelper::is_error($procResult)) {
            return $procResult;
        } else {
            return true;
        }
    }

    /**
     * @param $productId
     *
     * @return string
     */
    public function paymentUrl($productId)
    {
        return $this->weChatApplication->payment->scheme($productId);
    }

    public function notify()
    {
        return $this->weChatApplication->payment->handleNotify(function ($notify, $successful) {
            if ($successful) {
                //ToDo  modify logic
                $order = $this->prizePaymentService->find(['order_id' => $notify->out_trade_no]);
                if ($order && $order->isCommit()) {
                    $prize = $order->prize;
                    if ($prize && !$prize->isValid()) {
                        if ($prize->setIsValid()) {
                            Log::debug('支付成功:' . $notify->out_trade_no);
                            return $order->paid();
                        }
                    }
                }
            }

            return false;
        });
    }

    /**
     * @param        $orderId
     * @param        $money
     * @param string $tradeType
     * @param        $describe
     * @param string $detail
     *
     * @return bool|array
     */
    public function prepareOrder($orderId, $prizeId, $money, $tradeType = 'NATIVE', $describe, $detail = '')
    {
        if (empty($detail)) {
            $detail = $describe;
        }
        $payment = $this->weChatApplication->payment;
        $order = $this->createOrder($orderId, $prizeId, $money, $tradeType, $describe, $detail);
        $result = $payment->prepare($order);
        if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
            return [
                'prepare' => $result,
                'order' => $order,
            ];
        }

        return false;
    }

    private function createOrder($orderId, $prizeId, $money, $tradeType = 'NATIVE', $describe, $detail)
    {
        $merchantId = $this->weChatApplication->merchant->merchant_id;
        $attributes = [
            'mch_id' => $merchantId,
            'trade_type' => $tradeType,
            'body' => $describe,
            'detail' => $detail,
            'out_trade_no' => $orderId,
            'product_id' => $prizeId,
            'notify_url' => config('payment.wechat.notify_url'),
            'total_fee' => $money * 100, // 单位：分
        ];
        return new Order($attributes);
    }

    public function sign($postData, $key)
    {
        ksort($postData);
        reset($postData);
        $data = $this->implode($postData);
        $data .= "&key=" . $key;

        return strtoupper(md5($data));
    }

    public function implode(array $assoc, $inGlue = '=', $outGlue = '&')
    {
        $return = '';
        foreach ($assoc as $name => $value) {
            $return .= $name . $inGlue . (string)$value . $outGlue;
        }

        return substr($return, 0, -strlen($outGlue));
    }
}
